#include <dlfcn.h>
#include <iostream>
#include <string>
#include <unordered_map>

// #include <python3.11/Python.h>

// 定义函数指针类型别名
// 基础类型定义
using PyObject = struct _object;  // Python 对象基础类型
using Py_ssize_t = ssize_t;

// Unicode 相关函数
using PyUnicode_FromStringFunc = PyObject*(*)(const char*);
using PyUnicode_AsUTF8StringFunc = PyObject*(*)(PyObject*);  // 新增的定义
using PyUnicode_AsUTF8Func = const char*(*)(PyObject*);      // Python 3.3+ 更高效的版本

// 其他常用函数...
using Py_IsInitializedFunc = int(*)();
using Py_InitializeFunc = void(*)();
using Py_FinalizeFunc = void(*)();
using Py_DecRefFunc = void(*)(PyObject*);
using PySys_GetObjectFunc = PyObject*(*)(const char*);

class PythonVMWrapper {
public:
    // 构造函数：尝试链接到已加载的 Python 库或加载共享库
    PythonVMWrapper(const std::string& libPath = "") : is_linked(false) {
        if (!libPath.empty()) {
            handle = dlopen(libPath.c_str(), RTLD_LAZY | RTLD_GLOBAL);
            if (!handle) {
                throw std::runtime_error("无法加载库: " + std::string(dlerror()));
            }
        } else {
            // 假设已经在编译时链接了 Python 库
            handle = nullptr;
        }

        // 尝试获取已链接的 Python 函数地址
        mPy_IsInitialized = reinterpret_cast<Py_IsInitializedFunc>(dlsym(RTLD_DEFAULT, "Py_IsInitialized"));
        if (mPy_IsInitialized) {
            is_linked = true;
        } else {
            // 如果无法找到，尝试从共享库中加载
            if (handle) {
                mPy_IsInitialized = reinterpret_cast<Py_IsInitializedFunc>(dlsym(handle, "Py_IsInitialized"));
                if (!mPy_IsInitialized) {
                    throw std::runtime_error("无法找到 Py_IsInitialized 函数");
                }
            } else {
                throw std::runtime_error(
                    "无法找到已链接的 Python 库，请确保:\n"
                    "1. 已正确链接 Python 库，或\n"
                    "2. 提供共享库路径参数");
            }
        }

        // 预加载其他常用函数
        mPy_Initialize = getFunction<Py_InitializeFunc>("Py_Initialize");
        mPy_Finalize = getFunction<Py_FinalizeFunc>("Py_Finalize");
        mPy_DecRef = getFunction<Py_DecRefFunc>("Py_DecRef");
    }

    // 析构函数：卸载共享库（如果使用了动态加载）
    ~PythonVMWrapper() {
        if (handle) {
            dlclose(handle);
        }
    }

    // 检查是否链接到 Python 库
    bool isLinked() const {
        return is_linked;
    }

    // 统一的函数指针获取接口
    template<typename FuncType>
    FuncType getFunction(const std::string& funcName) const {
        // 优先尝试从已链接的库中获取函数地址
        if (is_linked) {
            FuncType func = reinterpret_cast<FuncType>(dlsym(RTLD_DEFAULT, funcName.c_str()));
            if (func) {
                return func;
            }
        }

        // 如果失败，并且使用了动态加载，则尝试从共享库中加载
        if (handle) {
            FuncType func = reinterpret_cast<FuncType>(dlsym(handle, funcName.c_str()));
            if (func) {
                return func;
            }
        }

        throw std::runtime_error("无法找到函数: " + funcName);
    }

    // 常用函数的直接访问方法
    Py_IsInitializedFunc getPyIsInitialized() const { return mPy_IsInitialized; }
    Py_InitializeFunc getPyInitialize() const { return mPy_Initialize; }
    Py_FinalizeFunc getPyFinalize() const { return mPy_Finalize; }
    Py_DecRefFunc getPyDecRef() const { return mPy_DecRef; }

private:
    void* handle = nullptr;          // 共享库句柄（如果使用了动态加载）
    bool is_linked = false;          // 是否链接到 Python 库的标志
    
    // 常用函数指针
    Py_IsInitializedFunc mPy_IsInitialized = nullptr;
    Py_InitializeFunc mPy_Initialize = nullptr;
    Py_FinalizeFunc mPy_Finalize = nullptr;
    Py_DecRefFunc mPy_DecRef = nullptr;
};


// 示例使用
int main(int argc, char* argv[]) {
    // if (Py_IsInitialized()) {
    //     std::cout << "Python 已经初始化" << std::endl;
    // } else {
    //     std::cout << "Python 未初始化，正在初始化..." << std::endl;
    //     Py_Initialize();
    //     std::cout << "Python 初始化成功" << std::endl;
    // }
    try {
        // 创建 PythonVMWrapper 实例
        PythonVMWrapper pythonVM(argc > 1 ? argv[1] : "/usr/lib/x86_64-linux-gnu/libpython3.11.so");
        
        std::cout << "Python 库链接方式: " 
                  << (pythonVM.isLinked() ? "静态链接" : "动态加载") 
                  << std::endl;

        // 获取并调用 Py_IsInitialized
        auto Py_IsInitialized = pythonVM.getPyIsInitialized();
        if (Py_IsInitialized()) {
            std::cout << "Python 已经初始化" << std::endl;
        } else {
            std::cout << "Python 未初始化，正在初始化..." << std::endl;
            // 获取并调用 Py_Initialize
            auto Py_Initialize = pythonVM.getPyInitialize();
            Py_Initialize();
            if (!Py_IsInitialized()) {
                std::cerr << "Python 初始化失败" << std::endl;
                return 1;
            }
            std::cout << "Python 初始化成功" << std::endl;
        }

        // 获取并调用 PySys_GetObject
        auto PySys_GetObject = pythonVM.getFunction<PySys_GetObjectFunc>("PySys_GetObject");
        PyObject* sys = PySys_GetObject("path"); // 获取 sys.path
        if (!sys) {
            std::cerr << "获取 sys.path 失败" << std::endl;
            return 1;
        }

        // 获取并调用 PyUnicode_FromString
        auto PyUnicode_FromString = pythonVM.getFunction<PyUnicode_FromStringFunc>("PyUnicode_FromString");
        PyObject* unicodeStr = PyUnicode_FromString("你好，Python!"); // 创建 Unicode 字符串
        if (!unicodeStr) {
            std::cerr << "创建 Unicode 字符串失败" << std::endl;
            return 1;
        }
        // 将 PyObject 的 sys.path 转为 C++ 字符串
        auto PyUnicode_AsUTF8 = pythonVM.getFunction<PyUnicode_AsUTF8Func>("PyUnicode_AsUTF8");
        const char* utf8Str = PyUnicode_AsUTF8(unicodeStr);


        // 打印 sys.path 和 Unicode 字符串
        std::cout << "sys.path: " << sys << std::endl;
        std::cout << "Unicode 字符串: " << unicodeStr << std::endl;
        std::cout << "Utf8 字符串内容: " << utf8Str << std::endl;

        // 使用后减少引用计数
        auto Py_DecRef = pythonVM.getPyDecRef();
        Py_DecRef(unicodeStr);

        // 程序结束前清理 Python
        auto Py_Finalize = pythonVM.getPyFinalize();
        Py_Finalize();

    } catch (const std::exception& ex) {
        std::cerr << "异常: " << ex.what() << std::endl;
        return 1;
    }

    return 0;
}